package com.hulk.Idempotent;


import com.hulk.Idempotent.annotation.Limitb;
import com.hulk.Idempotent.enums.LimitType;
import com.hulk.Idempotent.exception.LimitbException;
import com.hulk.Idempotent.util.LimitStrategy;
import com.hulk.Idempotent.util.LimitbKeyParser;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.redis.core.RedisTemplate;

@Slf4j
@Aspect
@AllArgsConstructor
public class LimitbInterceptor {



    public static final String LIMITD_NAME_PREFIX = "limitb";
    public static final String LIMITD_NAME_SEPARATOR = ".";

    //private RedisTemplate<String, Object> limitbRedisTemplate;

    private LimitbKeyParser limitbKeyParser;



    @Before(value = "@annotation(limitb)")
    @SneakyThrows
    public void joinPoint(JoinPoint joinPoint,Limitb limitb)  {


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LimitType limitType = limitb.limitType();
        long  maxCount =  limitb.maxCount();
        long  seconds =  limitb.seconds();
        String limitKeyName= limitbKeyParser.getKeyName(joinPoint,limitb);
        String limitName = LIMITD_NAME_PREFIX+LIMITD_NAME_SEPARATOR+getName(limitb.name(), signature)+limitKeyName;
        String clazz = limitType.getClazz();
        Class  cls = Class.forName(clazz);
        LimitStrategy strategy = (LimitStrategy) cls.newInstance();
        boolean b = strategy.execute(limitName,limitb);

        if(!b){
            throw new LimitbException(limitName + ":请求频率过高，在" + seconds + "内不能超过," + maxCount + "笔请求.");
        }
        return;
    }



    private String getName(String annotationName, MethodSignature signature) {
        if (annotationName.isEmpty()) {
            return String.format("%s.%s", signature.getDeclaringTypeName(), signature.getMethod().getName());
        } else {
            return annotationName;
        }
    }
}